package com.newly.center.business.service.impl;


import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.newly.center.business.compenont.WebSocketServer;
import com.newly.center.business.service.CheckRecordService;
import com.newly.center.business.service.MQTTReceiverService;
import com.newly.center.business.service.MediaService;
import com.newly.center.business.service.VehicleService;
import com.newly.common.base.entity.business.Po.*;
import com.newly.common.base.entity.business.Vo.CheckRecordVo;
import com.newly.common.base.entity.business.Vo.DetailsVo;
import com.newly.common.base.entity.device.po.DevicePo;
import com.newly.common.base.entity.sys.dict.po.DictPo;
import com.newly.common.base.exception.NewlyException;
import com.newly.common.core.utils.HttpUtil;
import com.newly.common.mapper.business.*;
import com.newly.common.mapper.sys.DeviceMapper;
import com.newly.common.mapper.sys.DictMapper;
import com.newly.driver.mqtt.utils.MqttUtils;
import com.newly.driver.mqtt.utils.ReturnResult;
import com.newly.transfer.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.json.JsonParseException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;

@Slf4j
@Service("mqttReceiverService")
public class MQTTReceiverServiceImpl implements MQTTReceiverService {
    @Autowired
    RedisUtils redisUtils;
    @Autowired
    SiteMapper siteMapper;
    @Autowired
    DeviceMapper deviceMapper;
    @Autowired
    DictMapper dictMapper;
    @Autowired
    VehicleMapper vehicleMapper;
    @Autowired
    CheckRecordMapper checkRecordMapper;
    @Autowired
    MediaMapper mediaMapper;
    @Autowired
    UploadRecordMapper uploadRecordMapper;
    @Autowired
    MediaService mediaService;
    @Autowired
    CheckRecordService checkRecordService;
    @Autowired
    VehicleService vehicleService;

    @Override
    public void register(String topic, String messageStr){
        JSONObject message = JSONUtil.parseObj(messageStr);
        DictPo dictPo = dictMapper.selectOne(new QueryWrapper<DictPo>().lambda().eq(DictPo::getCode, "10025"));
        String secret = dictPo==null?"8c1db015-f067-42d8-b707-872ef2770ff4":dictPo.getValue();
        JSONObject result = new JSONObject();
        JSONObject params = new JSONObject();
        try {
            params = JSONUtil.parseObj(message.getStr("params"));
        } catch (JsonParseException e) {
            throw e;
        }
        params = JSONUtil.parseObj(message.getStr("params"));
        String productKey = params.getStr("product-key");
        String cnonce = params.getStr("cnonce");
        String algorithm = params.getStr("algorithm");
        String sign = params.getStr("sign");
        long expires = Long.parseLong(params.getStr("expires"));

        //根据productKey，cnonce，secret生成sign
        String signText = productKey + ":" + cnonce + ":" + secret;
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("SHA");
        } catch (NoSuchAlgorithmException e) {
            result = ReturnResult.error(message, "-32000");
            MqttUtils.responseMessage(topic, result);
        }
        byte[] cipherBytes = messageDigest.digest(signText.getBytes());
        String realSign = Base64.getEncoder().encodeToString(cipherBytes);

        //生成的sign比对请求中的sign,如果吻合则存库并返回成功
        if (realSign.equals(sign)) {

            UUID uuid = UUID.randomUUID();
            JSONObject data = new JSONObject();
            data.put("token", uuid.toString());
            result = ReturnResult.successRegister(message, data);
            MqttUtils.responseMessage(topic, result);
            redisUtils.set("mqtt"+productKey,uuid.toString(),5400);

            String gatewayStr = redisUtils.get("mqttGateway",String.class);
            JSONArray gateway = new JSONArray("[]");
            if(gatewayStr==null||"".equals(gatewayStr)){
                gateway = new JSONArray("[]");
            }else {
                gateway= JSONUtil.parseArray(gatewayStr);
            }
            if(!gateway.contains(productKey)) gateway.add(productKey);
            redisUtils.set("mqttGateway",JSONUtil.toJsonStr(gateway));
        } else {
            result = ReturnResult.error(message, "-32000");
            MqttUtils.responseMessage(topic, result);
        }
    }

    @Override
    public void setVehicleInfo(String topic, String messageStr) {
        JSONObject message = JSONUtil.parseObj(messageStr);
        JSONObject result = new JSONObject();
        UploadRecord uploadRecord = new UploadRecord();
        //站点网关id
        String productKey = message.getStr("id");
        JSONObject params = message.getJSONObject("params");
        if(params==null){
            return;
        }
        JSONObject vehicle = params.getJSONObject("vehicle");
        String plateNo = vehicle.getStr("plate-no");
        uploadRecord.setOriginalPlate(plateNo);

        plateNo = StringUtils.isEmpty(plateNo)?"误识别"+DateUtil.now():plateNo.length()>6?plateNo:"误识别"+DateUtil.now();
        String platePicUrl = vehicle.getStr("plate-pic-url");
        String vehiclePic1 = vehicle.getStr("vehicle-pic1-url");
        String vehiclePic2 = vehicle.getStr("vehicle-pic2-url");
        String vehiclePic3 = vehicle.getStr("vehicle-pic3-url");
        String vehiclePic4 = vehicle.getStr("vehicle-pic4-url");
        String videoUrl = vehicle.getStr("video-url");
        String videoUrl2 = vehicle.getStr("wheels-video-url");
        String deviceSlot = vehicle.getStr("device-slot");

        String time = vehicle.getStr("time").replace("_"," ");
//        time = ToDBC(time);
        int axleNum = vehicle.getInt("wheels");
        int weight = vehicle.getInt("weight");

        int isOverload = 0;
        int isBlacklist = 0;

        uploadRecord.setOriginal_wheel(axleNum+"");
        uploadRecord.setDevice_id(productKey);
        uploadRecord.setUploadTime(time);

        if(axleNum==0){
            log.info("接收数据的轴数为0，不保存");
            return;
        }
        axleNum = axleNum<2?2:axleNum>6?6:axleNum;
        uploadRecord.setNew_wheel(axleNum+"");
        if(weight==0){
            log.info("接收数据的重量为0，不保存");
            return;
        }

        //图片视频文件补充ftp路径，车牌去掉第一位的颜色字(黄桂E88888）
//        plateNo=!"".equals(plateNo)?"http://192.168.1.211:9520/files/"+plateNo:plateNo;
        platePicUrl=!"".equals(platePicUrl)&&platePicUrl!=null?"http://180.142.131.36:18061/newly/"+platePicUrl:platePicUrl;
        vehiclePic1=!"".equals(vehiclePic1)&&vehiclePic1!=null?"http://180.142.131.36:18061/newly/"+vehiclePic1:vehiclePic1;
        vehiclePic2=!"".equals(vehiclePic2)&&vehiclePic2!=null?"http://180.142.131.36:18061/newly/"+vehiclePic2:vehiclePic2;
        vehiclePic3=!"".equals(vehiclePic3)&&vehiclePic3!=null?"http://180.142.131.36:18061/newly/"+vehiclePic3:vehiclePic3;
        vehiclePic4=!"".equals(vehiclePic4)&&vehiclePic4!=null?"http://180.142.131.36:18061/newly/"+vehiclePic4:vehiclePic4;
        videoUrl=!"".equals(videoUrl)&&videoUrl!=null?"http://180.142.131.36:18061/newly/"+videoUrl:videoUrl;
        videoUrl2=!"".equals(videoUrl2)&&videoUrl2!=null?"http://180.142.131.36:18061/newly/"+videoUrl2:videoUrl2;

        uploadRecord.setVideo1(videoUrl);
        uploadRecord.setVideo2(videoUrl2);

        DictPo ocrSite = dictMapper.selectById(56);
        DictPo forceOcrSite = dictMapper.selectById(57);
        if((plateNo.contains("误识别")&&(ocrSite.getValue().contains(productKey)))||forceOcrSite.getValue().contains(productKey)){
            List<String> picList = new ArrayList<>();
            if(platePicUrl!=null&&!platePicUrl.equals("")){
                picList.add(platePicUrl);
            }
            if(vehiclePic1!=null&&!vehiclePic1.equals("")){
                picList.add(vehiclePic1);
            }
            if(vehiclePic2!=null&&!vehiclePic2.equals("")){
                picList.add(vehiclePic2);
            }
            if(vehiclePic3!=null&&!vehiclePic3.equals("")){
                picList.add(vehiclePic3);
            }
            if(vehiclePic4!=null&&!vehiclePic4.equals("")){
                picList.add(vehiclePic4);
            }
            for(String pic : picList){
                try {
                    String tmpPlateNo = HttpUtil.postGeneralUrl("http://192.168.3.3:8088/licensePlate?url="+pic,"");
                    if(tmpPlateNo!=null&&!tmpPlateNo.equals("")){
                        plateNo = tmpPlateNo;
                        uploadRecord.setNew_wheel(plateNo);
                        break;
                    }
                }catch (Exception e){
                    log.info(e.getMessage());
                }

            }
        }
        if(plateNo.contains("挂")){
            log.info("车牌:"+plateNo+"不保存");
            return;
        }

        uploadRecordMapper.insert(uploadRecord);

        //查询轴数限重参数
        DictPo dictPo = dictMapper.selectById(32 + axleNum);

        //判断是否重复插入
        List<DevicePo> devicePos = deviceMapper.selectList(new QueryWrapper<DevicePo>().lambda()
                .eq(DevicePo::getProductKey, productKey).eq(DevicePo::getSlot, deviceSlot).ne(DevicePo::getType, 3));
        String deviceId="";
        if(devicePos.size()>0){
            deviceId=devicePos.get(0).getId().toString();
        }else {
            //未知设备上报
            deviceId=productKey+"|"+deviceSlot;
        }
        List<CheckRecord> checkRecordList = this.checkRecordMapper.selectList(new LambdaQueryWrapper<CheckRecord>()
                .eq(CheckRecord::getDeviceId,deviceId).eq(CheckRecord::getCarNum, plateNo).orderByDesc(CheckRecord::getCreateTime));
        if(checkRecordList.size()>0){
            String createTime = checkRecordList.get(0).getCreateTime();
            long timeDifference = CalTime(time, createTime);
            if(timeDifference < 300)
            {
                log.info("同车牌上一条记录时间为："+createTime+",时间间隔过短不保存");
                return;
            }
        }

        //新牌照车辆添加到数据库
        List<DevicePo> devicePoList = this.deviceMapper.selectList(new LambdaQueryWrapper<DevicePo>().eq(DevicePo::getProductKey,productKey).eq(DevicePo::getIsDeleted,0));
        if (devicePoList.size() == 0)
            throw new NewlyException("网关id：" + productKey + "没有绑定设备");
        List<Site> sites = siteMapper.selectList(new QueryWrapper<Site>().lambda().eq(Site::getId, devicePoList.get(0).getSiteId()).eq(Site::getIsDeleted,0));
        if (sites.size() == 0)
            throw new NewlyException("siteId:" + devicePoList.get(0).getSiteId() + "没有查到站点记录！");
        List<Vehicle> vehicles = vehicleMapper.selectList(new QueryWrapper<Vehicle>().lambda().eq(Vehicle::getVehicleNumber, plateNo));
        if(vehicles.size()==0){
            addVehicle(dictPo,plateNo,axleNum);
        }else{
            //黑名单判断
            Integer blackName = vehicles.get(0).getBlackName();
            axleNum = vehicles.get(0).getAxleCount();
            if(blackName==1){
                isBlacklist = 1;
            }
        }
        //超载判断
        Boolean illegal = weight > Integer.parseInt(dictPo.getValue());
        if(illegal){
            isOverload = 1;
        }

        //添加记录
        int recordId = addRecord(deviceId,dictPo, sites.get(0), plateNo, axleNum, platePicUrl, videoUrl, videoUrl2, time, weight
                ,productKey,deviceSlot,vehiclePic1,vehiclePic2,vehiclePic3,vehiclePic4);

        //websocket推送消息给前端
        final int isOve = isOverload;
        final int isBla = isBlacklist;
        if(!plateNo.contains("误识别")&&(isOverload==1||isBlacklist==1)){
            CopyOnWriteArraySet<WebSocketServer> webSocketServerSet = WebSocketServer.getWebSocketServerSet();
//            DictPo delay = dictMapper.selectOne(new QueryWrapper<DictPo>().lambda().eq(DictPo::getCode,"10028"));
//            int delayMilliSecond = Integer.parseInt(delay.getValue());
            webSocketServerSet.forEach(t -> {
                try {
                    DetailsVo<CheckRecordVo> detailsById = checkRecordService.getDetailsById(recordId);
                    JSONObject data = new JSONObject();
                    data.put("type","all");
                    data.put("data",detailsById);
                    data.put("isOverload",isOve);
                    data.put("isBlacklist",isBla);
//                    Thread.sleep(delayMilliSecond);
                    t.SendMessage(JSONUtil.toJsonStr(data));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }

        System.out.print("1");
    }

    @Override
    public void setIllegalVehicleInfo(String topic, String messageStr) {
        JSONObject message = JSONUtil.parseObj(messageStr);
        JSONObject result = new JSONObject();
        JSONObject params = JSONUtil.parseObj(message.getStr("params"));
        System.out.print("1");
    }

    void addVehicle(DictPo dictPo,String plateNo,int axleNum){
        Vehicle vehicle = new Vehicle();
        vehicle.setVehicleNumber(plateNo);
        vehicle.setAxleCount(axleNum);
        double weight = 0;
        if(dictPo!=null){
            weight = Double.parseDouble(dictPo.getValue());
        }
        vehicle.setLoadCapacity(weight);
        vehicle.setIsDeleted(0);
//        vehicle.setUserBelong(1003L);//暂存租户
//        vehicle.setEnterpriseBelong(0L);//暂存企业
        vehicle.setCreateTime(DateUtil.now());
        if (!this.vehicleService.repeat(plateNo)) {
            vehicleMapper.insert(vehicle);
        }
    }

    int addRecord(String deviceId,DictPo dictPo,Site site,String plateNo,int axleNum,String platePicUrl,String videoUrl,String videoUrl2, String time,int weight
            ,String productKey,String deviceSlot,String vehiclePic1,String vehiclePic2,String vehiclePic3,String vehiclePic4){
        CheckRecord checkRecord = new CheckRecord();
        checkRecord.setSiteName(site.getName());
        checkRecord.setSiteId(site.getId());
        checkRecord.setAxleNum(axleNum);
        checkRecord.setCarNum(plateNo);
        double totalWeight = weight;
        checkRecord.setTotalWeight(totalWeight);
        checkRecord.setCreateTime(time);
        double stdWeight = Double.parseDouble(dictPo.getValue());
        checkRecord.setStdWeight(stdWeight);
        double overWeight = totalWeight>stdWeight?totalWeight-stdWeight:0;
        checkRecord.setOverWeight(overWeight);
        int illegal = 2;
//        List<DevicePo> devicePos = deviceMapper.selectList(new QueryWrapper<DevicePo>().lambda()
//                .eq(DevicePo::getProductKey, productKey).eq(DevicePo::getSlot, deviceSlot).ne(DevicePo::getType, 1));
//        if(devicePos.size()>0){
//            checkRecord.setDeviceId(devicePos.get(0).getId().toString());
//        }else {
//            //未知设备上报
//            checkRecord.setDeviceId(productKey+"|"+deviceSlot);
//        }
        checkRecord.setDeviceId(deviceId);

        if(totalWeight>stdWeight){
            illegal=1;
            checkRecord.setOverRate((totalWeight-stdWeight)/totalWeight);
        }else {
            checkRecord.setOverRate(0D);
        }
//        List<CheckRecord> checkRecordList = this.checkRecordMapper.selectList(new LambdaQueryWrapper<CheckRecord>().eq(CheckRecord::getDeviceId,checkRecord.getDeviceId()).eq(CheckRecord::getCreateTime,time));
//        if (checkRecordList.size() == 0) {
//            checkRecordMapper.insert(checkRecord);
//        }
        checkRecordMapper.insert(checkRecord);

        List<CheckRecord> checkRecords = checkRecordMapper.selectList(new QueryWrapper<CheckRecord>().lambda()
                .eq(CheckRecord::getCreateTime, time).eq(CheckRecord::getCarNum, plateNo).eq(CheckRecord::getTotalWeight, totalWeight));

        List<Media> mediaList = new ArrayList<>();

        Media media = new Media();
        media.setTypeCode("0");
        media.setType(1);
        media.setOrderId(checkRecords.get(0).getId()+"");
        media.setIsDeleted(0);
        media.setPictureUrl(platePicUrl);
        media.setCreateTime(time);
        media.setIsSave("1");
        media.setIsIllegal(illegal+"");
        if(!StringUtils.isEmpty(media.getPictureUrl())){
            mediaList.add(media);
        }

        Media media1 = new Media();
        media1.setTypeCode("1");
        media1.setType(1);
        media1.setOrderId(checkRecords.get(0).getId()+"");
        media1.setIsDeleted(0);
        media1.setPictureUrl(vehiclePic1);
        media1.setCreateTime(time);
        media1.setIsSave("1");
        media1.setIsIllegal(illegal+"");
        if(!StringUtils.isEmpty(media1.getPictureUrl())){
            mediaList.add(media1);
        }

        Media media2 = new Media();
        media2.setTypeCode("2");
        media2.setType(1);
        media2.setOrderId(checkRecords.get(0).getId()+"");
        media2.setIsDeleted(0);
        media2.setPictureUrl(vehiclePic2);
        media2.setCreateTime(time);
        media2.setIsSave("1");
        media2.setIsIllegal(illegal+"");
        if(!StringUtils.isEmpty(media2.getPictureUrl())){
            mediaList.add(media2);
        }

        Media media3 = new Media();
        media3.setTypeCode("3");
        media3.setType(1);
        media3.setOrderId(checkRecords.get(0).getId()+"");
        media3.setIsDeleted(0);
        media3.setPictureUrl(vehiclePic3);
        media3.setCreateTime(time);
        media3.setIsSave("1");
        media3.setIsIllegal(illegal+"");
        mediaList.add(media3);
        if(!StringUtils.isEmpty(media3.getPictureUrl())){
            mediaList.add(media3);
        }

        Media media4 = new Media();
        media4.setTypeCode("4");
        media4.setType(1);
        media4.setOrderId(checkRecords.get(0).getId()+"");
        media4.setIsDeleted(0);
        media4.setPictureUrl(vehiclePic4);
        media4.setCreateTime(time);
        media4.setIsSave("1");
        media4.setIsIllegal(illegal+"");
        if(!StringUtils.isEmpty(media4.getPictureUrl())){
            mediaList.add(media4);
        }

        Media video2 = new Media();
        video2.setType(2);
        video2.setTypeCode("5");
        video2.setOrderId(checkRecords.get(0).getId()+"");
        video2.setIsDeleted(0);
        video2.setPictureUrl(videoUrl2);
        video2.setCreateTime(time);
        video2.setIsSave("1");
        video2.setIsIllegal(illegal+"");
        if(!StringUtils.isEmpty(video2.getPictureUrl())){
            mediaList.add(video2);
        }

        Media video = new Media();
        video.setType(2);
        video.setOrderId(checkRecords.get(0).getId()+"");
        video.setIsDeleted(0);
        video.setPictureUrl(videoUrl);
        video.setCreateTime(time);
        video.setIsSave("1");
        video.setIsIllegal(illegal+"");
        if(!StringUtils.isEmpty(video.getPictureUrl())){
            mediaList.add(video);
        }

//        mediaService.saveBatch(mediaList);
        if(mediaList.size()>0){
            mediaMapper.saveBatchMedia(mediaList);
        }else {
            log.info("无图片可存库");
        }
        return checkRecords.get(0).getId();

    }

    /**
     * 全角空格转半角空格
     * @param str
     * @return
     */
    public static String ToDBC(String str) {
        char c[] = str.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (c[i] == '\u00a0') {
                c[i] = ' ';
            }
        }
        String returnString = new String(c);
        return returnString;
    }

    // 计算两个时间差，返回为秒。
    private static long CalTime(String time1, String time2) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long second = 0L;
        try {
            Date d1 = df.parse(time1);
            Date d2 = df.parse(time2);
            long diff = d1.getTime() - d2.getTime();
            second = Math.abs(diff / (1000));
        } catch (ParseException e) {
            System.out.println("抱歉，时间日期解析出错。");
        }
        return second;
    }
}
